// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging

grammar krl;

/*
    This file is the grammar for the KUKA Robot Language.
    Copyright (C) 2010-2011  Jan Schlößin
    
    This grammar is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/*
Antlr4 port by Tom Everett, 2016
*/
module
    : (moduleData | moduleRoutines) EOF
    ;

moduleRoutines
    : mainRoutine (subRoutine | NEWLINE)*
    ;

mainRoutine
    : procedureDefinition
    | functionDefinition
    ;

subRoutine
    : procedureDefinition
    | functionDefinition
    ;

procedureDefinition
    : GLOBAL? DEF procedureName formalParameters NEWLINE routineBody END
    ;

procedureName
    : IDENTIFIER
    ;

functionDefinition
    : GLOBAL? DEFFCT type_ functionName formalParameters NEWLINE routineBody ENDFCT
    ;

functionName
    : IDENTIFIER
    ;

moduleData
    : DEFDAT moduleName PUBLIC? NEWLINE dataList ENDDAT NEWLINE*
    ;

moduleName
    : IDENTIFIER
    ;

dataList
    : (
        NEWLINE
        | forwardDeclaration NEWLINE
        | typeDeclaration NEWLINE
        | variableDeclarationInDataList NEWLINE
        | arrayInitialisation NEWLINE
        | importStatement NEWLINE
    )*
    ;

arrayInitialisation
    : IDENTIFIER arrayVariableSuffix '=' unaryPlusMinuxExpression
    ;

typeDeclaration
    : structureDefinition
    | enumDefinition
    ;

structureDefinition
    : GLOBAL? STRUC typeName type_ variableName variableListRest (
        ',' type_ variableName variableListRest
    )*
    ;

enumDefinition
    : GLOBAL? ENUM typeName enumValue (',' enumValue)*
    ;

enumValue
    : IDENTIFIER
    ;

variableDeclaration
    : DECL? (type_ variableName variableListRest | signalDeclaration)
    ;

signalDeclaration
    : SIGNAL IDENTIFIER primary (TO primary)?
    ;

variableDeclarationInDataList
    : DECL? GLOBAL? CONST? (
        type_ variableName (variableListRest | variableInitialisation)
        | signalDeclaration
    )
    ;

variableListRest
    : (',' variableName)*
    ;

variableInitialisation
    : '=' unaryPlusMinuxExpression
    ;

structLiteral
    : '{' (typeName ':')? structElementList '}'
    ;

structElementList
    : structElement (',' structElement)*
    ;

structElement
    : variableName unaryPlusMinuxExpression
    ;

formalParameters
    : '(' (parameter (',' parameter)*)? ')'
    ;

parameter
    : variableName (parameterCallType)?
    ;

routineBody
    : routineDataSection routineImplementationSection
    ;

routineDataSection
    : (
        forwardDeclaration NEWLINE
        | variableDeclaration NEWLINE
        | (NEWLINE) NEWLINE
        | importStatement NEWLINE
    )*
    ;

forwardDeclaration
    : EXT procedureName formalParametersWithType
    | EXTFCT type_ functionName formalParametersWithType
    ;

formalParametersWithType
    : '(' (parameterWithType (',' parameterWithType)*)? ')'
    ;

parameterWithType
    : type_ (parameterCallType)?
    ;

parameterCallType
    : ':' IDENTIFIER
    ;

importStatement
    : IMPORT type_ variableName IS '/R1/' moduleName '..' variableName
    ;

variableName
    : IDENTIFIER (arrayVariableSuffix)?
    ;

// expression in arrays are optional: a string literal can be assigned to a char array as a whole
arrayVariableSuffix
    : '[' (expression (',' (expression (',' expression?)?)?)?)? ']'
    ;

routineImplementationSection
    : statementList
    ;

statementList
    : statement*
    ;

statement
    : CONTINUE NEWLINE
    | EXIT NEWLINE
    | FOR IDENTIFIER '=' expression TO expression (IDENTIFIER expression)? NEWLINE statementList ENDFOR
    | GOTO IDENTIFIER NEWLINE
    | HALT NEWLINE
    | IF expression THEN NEWLINE statementList (ELSE NEWLINE statementList)? ENDIF NEWLINE
    | LOOP NEWLINE statementList ENDLOOP NEWLINE
    | REPEAT NEWLINE statementList UNTIL expression NEWLINE
    | SWITCH expression NEWLINE switchBlockStatementGroups ENDSWITCH NEWLINE
    | WAIT FOR expression NEWLINE
    | WAIT SEC expression NEWLINE
    | WHILE expression NEWLINE statementList ENDWHILE NEWLINE
    | RETURN (assignmentExpression)? NEWLINE
    | BRAKE (IDENTIFIER)? NEWLINE
    | assignmentExpression NEWLINE
    | IDENTIFIER ':' NEWLINE
    | NEWLINE
    | GLOBAL? INTERRUPT DECL primary WHEN expression DO assignmentExpression NEWLINE
    | INTERRUPT IDENTIFIER primary? NEWLINE
    | (PTP | PTP_REL) geometricExpression (C_PTP (C_DIS | C_ORI | C_VEL)?)? NEWLINE
    | LIN geometricExpression (C_DIS | C_ORI | C_VEL)? NEWLINE
    | LIN_REL geometricExpression (C_DIS | C_ORI | C_VEL)? enumElement? NEWLINE
    | (CIRC | CIRC_REL) geometricExpression ',' geometricExpression (',' IDENTIFIER primary)? (
        C_DIS
        | C_ORI
        | C_VEL
    )? NEWLINE
    | TRIGGER WHEN (IDENTIFIER) '=' expression DELAY '=' expression DO assignmentExpression (
        PRIO '=' expression
    )? NEWLINE
    | analogInputStatement NEWLINE
    | analogOutputStatement NEWLINE
    ;

analogOutputStatement
    : ANOUT (IDENTIFIER assignmentExpression (IDENTIFIER '=' literal)* | IDENTIFIER IDENTIFIER)
    ;

analogInputStatement
    : ANIN (IDENTIFIER assignmentExpression | IDENTIFIER IDENTIFIER)
    ;

switchBlockStatementGroups
    : NEWLINE* (caseLabel statementList)+ (defaultLabel statementList)?
    ;

caseLabel
    : CASE expression (',' expression)* NEWLINE
    ;

defaultLabel
    : DEFAULT NEWLINE
    ;

expressionList
    : assignmentExpression (',' assignmentExpression)*
    ;

assignmentExpression
    : expression ('=' expression)*
    ;

expression
    : conditionalOrExpression (relationalOp conditionalOrExpression)*
    ;

relationalOp
    : '=='
    | '<>'
    | '<='
    | '>='
    | '<'
    | '>'
    ;

conditionalOrExpression
    : exclusiveOrExpression ((OR | B_OR) exclusiveOrExpression)*
    ;

exclusiveOrExpression
    : conditionalAndExpression ((EXOR | B_EXOR) conditionalAndExpression)*
    ;

conditionalAndExpression
    : additiveExpression ((AND | B_AND) additiveExpression)*
    ;

additiveExpression
    : multiplicativeExpression (('+' | '-') multiplicativeExpression)*
    ;

multiplicativeExpression
    : geometricExpression (('*' | '/') geometricExpression)*
    ;

geometricExpression
    : unaryNotExpression (':' unaryNotExpression)*
    ;

unaryNotExpression
    : NOT unaryNotExpression
    | B_NOT unaryNotExpression
    | unaryPlusMinuxExpression
    ;

unaryPlusMinuxExpression
    : '+' unaryPlusMinuxExpression
    | '-' unaryPlusMinuxExpression
    | primary
    ;

primary
    : parExpression
    | variableName ('.' variableName)* (arguments)?
    | literal
    ;

parExpression
    : '(' assignmentExpression ')'
    ;

type_
    : primitiveType ('[' (INTLITERAL)? ']')?
    | typeName ('[' (INTLITERAL)? ']')?
    ;

typeName
    : IDENTIFIER
    ;

primitiveType
    : BOOL
    | CHAR
    | INT
    | REAL
    ;

arguments
    : '(' (expressionList)? ')'
    ;

literal
    : INTLITERAL
    | FLOATLITERAL
    | CHARLITERAL
    | STRINGLITERAL
    | structLiteral
    | TRUE
    | FALSE
    | enumElement
    ;

enumElement
    : '#' IDENTIFIER
    ;

AND
    : A N D
    ;

ANIN
    : A N I N
    ;

ANOUT
    : A N O U T
    ;

B_AND
    : B '_' A N D
    ;

B_NOT
    : B '_' N O T
    ;

B_OR
    : B '_' O R
    ;

B_EXOR
    : B '_' E X O R
    ;

BOOL
    : B O O L
    ;

BRAKE
    : B R A K E
    ;

C_DIS
    : C '_' D I S
    ;

C_ORI
    : C '_' O R I
    ;

C_PTP
    : C '_' P T P
    ;

C_VEL
    : C '_' V E L
    ;

CASE
    : C A S E
    ;

CAST_FROM
    : C A S T '_' F R O M
    ;

CAST_TO
    : C A S T '_' T O
    ;

CHAR
    : C H A R
    ;

CIRC_REL
    : C I R C '_' R E L
    ;

CIRC
    : C I R C
    ;

CONST
    : C O N S T
    ;

CONTINUE
    : C O N T I N U E
    ;

DELAY
    : D E L A Y
    ;

DECL
    : D E C L
    ;

DEF
    : D E F
    ;

DEFAULT
    : D E F A U L T
    ;

DEFDAT
    : D E F D A T
    ;

DEFFCT
    : D E F F C T
    ;

DO
    : D O
    ;

ELSE
    : E L S E
    ;

END
    : E N D
    ;

ENDDAT
    : E N D D A T
    ;

ENDFCT
    : E N D F C T
    ;

ENDFOR
    : E N D F O R
    ;

ENDIF
    : E N D I F
    ;

ENDLOOP
    : E N D L O O P
    ;

ENDSWITCH
    : E N D S W I T C H
    ;

ENDWHILE
    : E N D W H I L E
    ;

ENUM
    : E N U M
    ;

EXIT
    : E X I T
    ;

EXT
    : E X T
    ;

EXTFCT
    : E X T F C T
    ;

FALSE
    : F A L S E
    ;

FOR
    : F O R
    ;

GLOBAL
    : G L O B A L
    ;

GOTO
    : G O T O
    ;

HALT
    : H A L T
    ;

IF
    : I F
    ;

IMPORT
    : I M P O R T
    ;

INTERRUPT
    : I N T E R R U P T
    ;

INT
    : I N T
    ;

IS
    : I S
    ;

LIN_REL
    : L I N '_' R E L
    ;

LIN
    : L I N
    ;

LOOP
    : L O O P
    ;

MAXIMUM
    : M A X I M U M
    ;

MINIMUM
    : M I N I M U M
    ;

NOT
    : N O T
    ;

OR
    : O R
    ;

PRIO
    : P R I O
    ;

PTP_REL
    : P T P '_' R E L
    ;

PTP
    : P T P
    ;

PUBLIC
    : P U B L I C
    ;

REAL
    : R E A L
    ;

REPEAT
    : R E P E A T
    ;

RETURN
    : R E T U R N
    ;

SEC
    : S E C
    ;

SIGNAL
    : S I G N A L
    ;

STRUC
    : S T R U C
    ;

SWITCH
    : S W I T C H
    ;

THEN
    : T H E N
    ;

TO
    : T O
    ;

TRIGGER
    : T R I G G E R
    ;

TRUE
    : T R U E
    ;

UNTIL
    : U N T I L
    ;

WAIT
    : W A I T
    ;

WHEN
    : W H E N
    ;

WHILE
    : W H I L E
    ;

EXOR
    : E X O R
    ;

fragment A
    : ('a' | 'A')
    ;

fragment B
    : ('b' | 'B')
    ;

fragment C
    : ('c' | 'C')
    ;

fragment D
    : ('d' | 'D')
    ;

fragment E
    : ('e' | 'E')
    ;

fragment F
    : ('f' | 'F')
    ;

fragment G
    : ('g' | 'G')
    ;

fragment H
    : ('h' | 'H')
    ;

fragment I
    : ('i' | 'I')
    ;

fragment J
    : ('j' | 'J')
    ;

fragment K
    : ('k' | 'K')
    ;

fragment L
    : ('l' | 'L')
    ;

fragment M
    : ('m' | 'M')
    ;

fragment N
    : ('n' | 'N')
    ;

fragment O
    : ('o' | 'O')
    ;

fragment P
    : ('p' | 'P')
    ;

fragment Q
    : ('q' | 'Q')
    ;

fragment R
    : ('r' | 'R')
    ;

fragment S
    : ('s' | 'S')
    ;

fragment T
    : ('t' | 'T')
    ;

fragment U
    : ('u' | 'U')
    ;

fragment V
    : ('v' | 'V')
    ;

fragment W
    : ('w' | 'W')
    ;

fragment X
    : ('x' | 'X')
    ;

fragment Y
    : ('y' | 'Y')
    ;

fragment Z
    : ('z' | 'Z')
    ;

HEADERLINE
    : '&' ~ ('\n' | '\r')* ('\r\n' | '\r' | '\n' | EOF) -> skip
    ;

WS
    : (' ' | '\t' | '\u000C') -> skip
    ;

NEWLINE
    : '\r'? '\n'
    ;

LINE_COMMENT
    : ';' ~ ('\n' | '\r')* -> skip
    ;

CHARLITERAL
    : '\'' (EscapeSequence | ~ ('\'' | '\\' | '\r' | '\n')) '\''
    ;

STRINGLITERAL
    : '"' (EscapeSequence | ~ ('\\' | '"' | '\r' | '\n'))* '"'
    ;

fragment EscapeSequence
    : '\\' (
        'b'
        | 't'
        | 'n'
        | 'f'
        | 'r'
        | '"'
        | '\''
        | '\\'
        | ('0' .. '3') ('0' .. '7') ('0' .. '7')
        | ('0' .. '7') ('0' .. '7')
        | ('0' .. '7')
    )
    ;

FLOATLITERAL
    : ('0' .. '9')+ '.' ('0' .. '9')* Exponent?
    | '.' ('0' .. '9')+ Exponent?
    | ('0' .. '9')+ Exponent
    ;

fragment Exponent
    : E ('+' | '-')? ('0' .. '9')+
    ;

INTLITERAL
    : ('0' .. '9')+
    | HexPrefix HexDigit+ HexSuffix
    | BinPrefix BinDigit+ BinSuffix
    ;

fragment HexPrefix
    : '\'' H
    ;

fragment HexDigit
    : ('0' .. '9' | 'a' .. 'f' | 'A' .. 'F')
    ;

fragment HexSuffix
    : '\''
    ;

fragment BinPrefix
    : '\'' B
    ;

fragment BinDigit
    : ('0' | '1')
    ;

fragment BinSuffix
    : '\''
    ;

IDENTIFIER
    : IdentifierStart IdentifierPart*
    ;

fragment IdentifierStart
    : 'a' .. 'z'
    | 'A' .. 'Z'
    | '_'
    | '$'
    ;

fragment IdentifierPart
    : IdentifierStart
    | '0' .. '9'
    ;